package in.waffl.fairycake;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.io.IOException;
import java.util.ArrayList;

public class Monster extends Character {
	public static ArrayList<Monster> monsters = new ArrayList<Monster>();
	private Direction jumpDirection = null;
	private Character target;
	private int jumpTimer = 0;
	private boolean jumping = false;
	private final Canvas canvas;
	private final String type;
	public Monster(String type, int x, int y, Direction d, final Character target, final Canvas canvas) {
		super(x, y, 39, 20);
		this.type = type;
		this.canvas = canvas;
		synchronized (monsters) {
			monsters.add(this);
		}
		this.setDirection(d);
		this.target = target;
		this.setImageIndex(getDirection() == Direction.LEFT?1:4);
		String filename = type.substring(0, 1).toUpperCase() + type.substring(1) + ".png";
		try {
			setSprite(new Sprite(Ptolemy.class.getResourceAsStream("/in/waffl/fairycake/data/"+filename), 39, 48, Color.magenta));
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.drawable = new Drawable() {
			@Override
			public void draw(Graphics2D g) {
				getSprite().draw(g, canvas, getX(), getY()-29, getImageIndex());
			}
		};
		drawable.depth = -1;
		canvas.addDrawable(drawable);
	}
	@Override
	public void characterPoll(PollingThread p) {
		final int animationSpeed = 8;
		Rectangle footHoldRect = new Rectangle(getX() + 1, getY() + getHeight(), getWidth() - 2, 1 + Math.round(getVspeed()));
		Block footHold = Block.collisionRectangleTop(footHoldRect);
		Boolean pos = target.getX() < getX();
		Rectangle jumpTargetRect = new Rectangle(getX() + (pos?-41:1), getY()-60, getWidth() + 40, 60);
		Block jumpTarget = Block.collisionRectangleTop(jumpTargetRect);
		if (target.getY() + 20 < getY() && !isJumping()) {
			jumpTimer++;
		}
		if (jumpTimer > 20  && footHold != null && jumpTarget != null && !isJumping()) {
			setJumping(true);
			if (jumpTarget.getX() > getX() + 20) setDirection(jumpDirection = Direction.RIGHT);
			if (jumpTarget.getX() < getX() - 20) setDirection(jumpDirection = Direction.LEFT);
			jumpTimer = 0;
		}
		if (getVspeed() > 2) {
			setImageIndex((walkAnim/animationSpeed)%2+11);
			walkAnim += 1;
		} else {
			if (isJumping()) {
				jumpTimer++;
				if (jumpTimer < 30) {
					setImageIndex(getDirection()==Direction.LEFT?6:7);
				} else {
					if (getImageIndex() == 6 || getImageIndex() == 7) {
						setImageIndex(getDirection()==Direction.LEFT?1:4);
						setVspeed(jumpSpeed);
						if (jumpDirection == Direction.LEFT) setHspeed(0f - getWalkSpeed());
						if (jumpDirection == Direction.RIGHT) setHspeed(getWalkSpeed());
					}
					if ((getImageIndex() == 1 || getImageIndex() == 4) && getVspeed() > 0) {
						if (target.getY() >= getY()) {
							if (target.getX() > getX()) setDirection(Direction.RIGHT);
							if (target.getX() < getX()) setDirection(Direction.LEFT);
						}
						setJumping(false);
						if (target.getY() + 20 < getY()) {
							jumpTimer = 19;
						} else {
							jumpTimer = 0;
						}
					}
				}
			} else {
				Monster monstRight = getMonstRight();
				Monster monstLeft = getMonstLeft();
				if (getDirection() == Direction.RIGHT) {
					setImageIndex((walkAnim/animationSpeed)%3+3);
					Block collisionRight = Block.collisionRectangle(new Rectangle(getX()+getWidth(), getY(), 2, getHeight()));
					if ((collisionRight == null || collisionRight.getY() > getY() + getHeight() - 1)) {
						if (monstRight == null) {
							setX(getX() + getWalkSpeed());
						} else {
							int newX = monstRight.getX()-monstRight.getWidth();
							Block collTest = Block.collisionRectangle(new Rectangle(newX, getY(), getWidth(), getHeight()));
							if (collTest != null) newX = monstRight.getX()+monstRight.getWidth();
							setX(newX);
							setDirection(monstRight.getDirection());
							if (monstRight.getMonstRight() != null) {
								monstRight.getMonstRight().setDirection(getDirection());
							}	
						}
					} else if (footHold != null) {
						setDirection(Direction.LEFT);
						if (monstLeft != null) {
							monstLeft.setDirection(getDirection());
							if (monstLeft.getMonstLeft() != null) {
								monstLeft.getMonstLeft().setDirection(getDirection());
							}
						}
					}
					walkAnim += 1;
				}
				if (getDirection() == Direction.LEFT) {
					setImageIndex((walkAnim/animationSpeed)%3);
					Block collisionLeft = Block.collisionRectangle(new Rectangle(getX()-2, getY(), 2, getHeight()));
					if ((collisionLeft == null || collisionLeft.getY() > getY() + getHeight() - 1) /*&& monstLeft == null*/) {
						if (monstLeft == null) {
							setX(getX() - getWalkSpeed());
						} else {
							int newX = monstLeft.getX()+monstLeft.getWidth();
							Block collTest = Block.collisionRectangle(new Rectangle(newX, getY(), getWidth(), getHeight()));
							if (collTest != null) newX = monstLeft.getX()-monstLeft.getWidth();
							setX(newX);
							setDirection(monstLeft.getDirection());
							if (monstLeft.getMonstLeft() != null) {
								monstLeft.getMonstLeft().setDirection(getDirection());
							}
						}
					} else if (footHold != null) {
						setDirection(Direction.RIGHT);
						if (monstRight != null) {
							monstRight.setDirection(getDirection());
							if (monstRight.getMonstRight() != null) {
								System.out.println("Changing things right");
								monstRight.getMonstRight().setDirection(getDirection());
							}
						}
					}
					walkAnim += 1;
				}
			}
		}
	}
	public Monster getMonstRight() {
		return Monster.collisionRectangleBounds(new Rectangle(getX()+getWidth(), getY(), 2, getHeight()));
	}
	public Monster getMonstLeft() {
		return Monster.collisionRectangleBounds(new Rectangle(getX()-2, getY(), 2, getHeight()));
	}

	public static Monster collisionPoint(Point p) {
		synchronized (monsters) {
			for (Monster m : monsters) {
				if (p.x > m.getX() && p.x < m.getX() + m.getWidth()
						&& p.y > m.getY() && p.y < m.getY() + m.getHeight())
					return m;
			}
			return null;
		}
	}
	public static Monster collisionLine(Point p1, Point p2) {
		synchronized (monsters) {
			Line2D l = new Line2D.Float(p1, p2);
			for (Monster m : monsters) {
				if (l.intersects(m.getX(), m.getY(), m.getWidth(), m.getHeight())) return m;
			}
			return null;
		}
	}
	public static Monster collisionRectangleBounds(Rectangle r) {
		synchronized (monsters) {
			for (Monster m : monsters) {
				if (r.intersects(new Rectangle(m.getX(), m.getY(), m.getWidth(), m.getHeight()))) return m;
			}
			return null;
		}
	}
	public static Monster collisionRectangle(Rectangle r) {
		synchronized (monsters) {
			for (Monster m : monsters) {
				if (r.intersects(new Rectangle(m.getX(), m.getY() + 20 - m.getSprite().getHeight(), m.getWidth(), m.getSprite().getHeight()))) return m;
			}
			return null;
		}
	}
	public static void destroyAll() {
		synchronized (monsters) {
			for (Monster m : monsters) {
				m.destroy(false);
			}
			monsters.clear();
		}
	}
	private void destroy(boolean remove) {
		synchronized (monsters) {
			if (remove) {
				monsters.remove(this);
			}
			drawable.destroy = true;
		}
	}
	public void destroy() {
		destroy(true);
	}
	public void cakify() {
		new Cake(getX(), getY()-10, this.canvas, this, this.target);
		destroy();
	}
	protected void onLanding() {

	}
	public static int getMonsterQuantity() {
		return monsters.size();
	}
	public String getType() {
		return type;
	}
	protected void onDie() {
		new Angel(this, 9, canvas) {
			protected void onDestroy() {
				if (Monster.getMonsterQuantity() == 0 && Cake.getCakeCount() < 1) Main.getLogicExecutor().nextLevel();
			}
		};
	}
	public void triggerJump (Direction d) {
		setJumping(true);
		jumpDirection = d;
	}
	public boolean isJumping() {
		return jumping;
	}
	private void setJumping(boolean jumping) {
		this.jumping = jumping;
	}
}
